﻿// Decompiled with JetBrains decompiler
// Type: Netick.Unity.NetworkBehaviour
// Assembly: Netick.Unity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E128C7FD-39ED-4452-86AC-6EC748457030
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.xml

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

#nullable disable
namespace Netick.Unity;

/// <summary>
/// Base class for all networked behaviors in Netick.
/// Inherit from this class to create network-synchronized logic.
/// Provides access to network state, input, and misc utility methods.
/// </summary>
public abstract class NetworkBehaviour : NetickBehaviour, INetickNetworkScript, INetickScript
{
  public unsafe int* StatePtr;
  internal List<NetworkRpc> RelatedRPCs = new List<NetworkRpc>(8);

  List<NetworkRpc> INetickNetworkScript.RelatedRpcs
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)] get => this.RelatedRPCs;
  }

  int INetickNetworkScript.Index
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)] get => this.BehaviourId;
  }

  unsafe int* INetickNetworkScript.State
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)] get => this.StatePtr;
  }

  /// <summary>
  /// The network id of this <see cref="T:Netick.Unity.NetworkBehaviour" />.
  /// </summary>
  public int BehaviourId { get; internal set; }

  /// <summary>
  /// The network id of this <see cref="T:System.Object" />.
  /// </summary>
  public int Id => this.Entity.Id;

  public NetworkBehaviourRef<T> GetRef<T>() where T : NetworkBehaviour
  {
    return new NetworkBehaviourRef<T>(this);
  }

  /// <summary>
  /// Returns true if this <see cref="T:Netick.Unity.NetworkSandbox" /> is a client.
  /// </summary>
  public bool IsClient => this.Sandbox.IsClient;

  /// <summary>
  /// Returns true if this <see cref="T:Netick.Unity.NetworkSandbox" /> is the server.
  /// </summary>
  public bool IsServer => this.Sandbox.IsServer;

  /// <summary>
  /// Returns true if this <see cref="T:Netick.Unity.NetworkSandbox" /> is the owner of this Object. In this version of Netick: Server=Owner.
  /// </summary>
  public bool IsOwner => this.Sandbox.IsServer;

  /// <summary>
  /// Returns true if this <see cref="T:Netick.Unity.NetworkSandbox" /> is the host.
  /// </summary>
  public bool IsHost => this.Sandbox.IsHost;

  /// <summary>
  /// Returns true if this <see cref="T:Netick.Unity.NetworkSandbox" /> is a client or the host.
  /// </summary>
  public bool IsPlayer => this.Sandbox.IsPlayer;

  /// <summary>
  /// Returns true if this <see cref="P:Netick.Unity.NetworkSandbox.LocalPlayer" /> is providing inputs to this Object.
  /// </summary>
  public bool IsInputSource => this.Object.IsInputSource;

  /// <summary>
  /// Returns true if we neither provide inputs nor own this <see cref="T:System.Object" />.
  /// </summary>
  public bool IsProxy => this.Object.IsProxy;

  /// <summary>
  /// Returns true if we are currently resimulating a previous input of the past. On the server, it always returns false since <b>only the clients resimulate</b>.
  /// </summary>
  public bool IsResimulating => this.Engine.IsResimulating;

  /// <summary>
  /// On the client  returns true only if the client is predicting this object. On the server, always returns true.
  /// </summary>
  public bool IsPredicted
  {
    get
    {
      return this.IsServer || this.Object.IsInputSource || this.Object.PredictionMode == Relevancy.Everyone;
    }
  }

  /// <summary>
  /// On the client, returns true if this client is interested in this object. On the server, always returns true.
  /// </summary>
  public bool IsInterested => this.Entity.IsInterested;

  /// <summary>
  /// Returns the source <see cref="T:Netick.NetworkPlayer" /> (<see cref="T:Netick.NetworkPeer" />/<see cref="T:Netick.ServerConnection" />) of inputs for this <see cref="T:Netick.Unity.NetworkObject" />. If the source of inputs is remote (from a client) it returns that <see cref="T:Netick.ServerConnection" />, while on the
  /// input source itself it returns the local <see cref="T:Netick.NetworkPlayer" />.
  /// <para>Use <see cref="P:Netick.Unity.NetworkBehaviour.InputSourcePlayerId" /> for the synced-to-everyone player id of the Input Source - because <see cref="P:Netick.Unity.NetworkBehaviour.InputSource" /> is only valid in the client for objects the client itself is the input source of, and it's null for everything else.</para>
  /// </summary>
  public NetworkPlayer InputSource
  {
    get => this.Entity.InputSource;
    set => this.Entity.InputSource = value;
  }

  /// <summary>
  /// Returns the NetworkPlayerId of the input source of this object. This is synced to every client.
  /// </summary>
  public NetworkPlayerId InputSourcePlayerId => this.Entity.InputSourcePlayerId;

  /// <summary>
  /// Returns the networked state size of this behavior in bytes.
  /// </summary>
  public virtual int StateSize => this.InternalGetStateSizeWords() * 4;

  public unsafe BehaviourStateRef GetStateRef()
  {
    return new BehaviourStateRef(this.StateSize, (long) (int) (this.StatePtr - this.Entity.StatePtr), this.Entity.BlockIndex);
  }

  /// <summary>Copies the state of this behavior into target.</summary>
  public virtual unsafe void CopyStateTo(byte* target)
  {
    MemoryAllocation.Copy((void*) target, (void*) this.StatePtr, (long) this.StateSize);
  }

  /// <summary>Copies the state of this behavior into target.</summary>
  public virtual unsafe void CopyStateTo(byte[] target)
  {
    fixed (byte* target1 = target)
      this.CopyStateTo(target1);
  }

  public virtual unsafe void SetStateFrom(
    BehaviourStateRef stateRef,
    byte[] worldSnapshot,
    bool invokeOnChanged = true)
  {
    fixed (byte* worldSnapshot1 = worldSnapshot)
      this.SetStateFrom(stateRef, worldSnapshot1, invokeOnChanged);
  }

  public virtual unsafe void SetStateFrom(
    BehaviourStateRef stateRef,
    byte* worldSnapshot,
    bool invokeOnChanged = true)
  {
    this.Entity.SetStateFrom(worldSnapshot + stateRef.StateOffsetBytes, (int) (this.StatePtr - this.Entity.StatePtr), this.InternalGetStateSizeWords(), invokeOnChanged);
    this.NetcodeIntoGameEngine();
  }

  /// <summary>
  /// Sets the state of this behavior. Ignores InputSource Relevancy.
  /// </summary>
  /// <param name="source"></param>
  public virtual unsafe void SetStateFrom(byte* source, bool invokeOnChanged = true)
  {
    this.Entity.SetStateFrom(source, (int) (this.StatePtr - this.Entity.StatePtr), this.InternalGetStateSizeWords(), invokeOnChanged);
    this.NetcodeIntoGameEngine();
  }

  /// <summary>
  /// Sets the state of this behavior. Ignores InputSource Relevancy.
  /// </summary>
  public virtual unsafe void SetStateFrom(byte[] source, bool invokeOnChanged = true)
  {
    fixed (byte* source1 = source)
      this.SetStateFrom(source1, invokeOnChanged);
  }

  /// <summary>
  /// Zeros out the networked state memory of this behavior. Ignores InputSource Relevancy.
  /// </summary>
  public virtual unsafe void ClearState(bool invokeOnChanged = true)
  {
    int stateSizeWords = this.InternalGetStateSizeWords();
    int* source = stackalloc int[stateSizeWords];
    for (int index = 0; index < stateSizeWords; ++index)
      source[index] = 0;
    this.SetStateFrom((byte*) source, invokeOnChanged);
  }

  /// <summary>
  /// Fetches a network input for this tick. Returns false if no input source is currently providing inputs to this Object, or when input loss occurs (in case of a remote input source).
  /// </summary>
  public bool FetchInput<T>(out T input, int index = 0) where T : unmanaged
  {
    bool isDuplicated = false;
    return this.Engine.FetchInput<T>(out input, ref isDuplicated, this.Entity, index);
  }

  /// <summary>
  /// Fetches a network input for this tick. Returns false if no input source is currently providing inputs to this Object, or when input loss occurs (in case of a remote input source).
  /// </summary>
  public bool FetchInput<T>(out T input, out bool isDuplicated, int index = 0) where T : unmanaged
  {
    isDuplicated = false;
    return this.Engine.FetchInput<T>(out input, ref isDuplicated, this.Entity, index);
  }

  public unsafe Interpolator FindInterpolator(string propertyName)
  {
    SmoothMetaData smoothMetaData;
    return this.Entity.ObjectMeta.PropertyNameToSmoothMetaData.TryGetValue($"{((object) this).GetType().FullName}_{propertyName}", out smoothMetaData) ? new Interpolator(this.Entity, this.StatePtr, smoothMetaData.DataOffsetWords, smoothMetaData.Precision, smoothMetaData.VectorFloatFieldsCount) : new Interpolator();
  }

  /// <summary>
  /// Called in the client when the client becomes interested in this object.
  /// </summary>
  public virtual void OnBecameInterested()
  {
  }

  /// <summary>
  /// Called in the client when the client becomes uninterested in this object.
  /// </summary>
  public virtual void OnBecameUninterested()
  {
  }

  /// <summary>
  /// Called in the server (or the client if it is the input source) when the input source of this Object has changed.
  /// </summary>
  public virtual void OnInputSourceChanged(NetworkPlayer previous)
  {
  }

  /// <summary>
  /// Called on the server when the input source of this Object has disconnected.
  /// </summary>
  public virtual void OnInputSourceLeft()
  {
  }

  public virtual void NetworkAwake()
  {
  }

  [Obsolete("Use NetworkStart/NetworkAwake instead.")]
  public virtual void NetworkReset()
  {
  }

  public virtual void InternalInit()
  {
  }

  public virtual void InternalReset()
  {
  }

  public virtual int InternalGetStateSizeWords() => 0;
}
